﻿using System;
using System.Web;
using System.Web.Routing;
using ManagedUIFlow.Application;
using ManagedUIFlow.Infrastructure.Flows;
using ManagedUIFlow.Infrastructure.Services;
using ManagedUIFlow.Model;
using Moq;
using Xunit;

namespace ManagedUIFlow.Specs.Application
{
    public class AppHandlerSpecs
    {
        [Fact]
        public void ConstructorWithNullRequestContext_Throws()
        {
            Assert.Throws<ArgumentNullException>(() => new AppHandler(null));
        }

       
        [Fact]
        public void ProcessRequest_GetsFlowAndCallsExecute()
        {
            var flow = new ManagedFlow("foo");            
            var appControllerMock = new Mock<ApplicationController>();            
            var flowViewServiceBuilder = new FlowViewServiceBuilder();
            var flowViewServiceMock = new Mock<IFlowViewService>();   
            flowViewServiceBuilder.SetFlowViewService(flowViewServiceMock.Object);
            var context = new RequestContext(new Mock<HttpContextBase>().Object, new RouteData());
            var handler = new PublicAppHandler(context)
                              {
                                  ApplicationController = appControllerMock.Object,
                                  //FlowViewService = flowViewServiceMock.Object
                              };
            context.RouteData.Values.Add("controller", "foo");
            context.RouteData.Values.Add("action", "bar");
            flowViewServiceMock.Setup(s => s.Deserialize("foo", context)).Returns(flow);
            handler.FlowViewServiceBuilder = flowViewServiceBuilder;    

            handler.PublicProcessRequest(context.HttpContext);

            appControllerMock.Verify(a => a.Execute(context, flow));
        }

        [Fact]
        public void ProcessRequest_StartsNewFlow()
        {
            var flowDefinition = new Flow("foo", "", RedirectBehavior.Auto, "");
            var flowServiceMock = new Mock<FlowService>();
            flowServiceMock.Setup(s => s.GetFlowDefinition("foo")).Returns(flowDefinition);
            var appControllerMock = new Mock<ApplicationController>();           
            var context = new RequestContext(new Mock<HttpContextBase>().Object, new RouteData());
            var handler = new PublicAppHandler(context)
            {
                ApplicationController = appControllerMock.Object,
                FlowService = flowServiceMock.Object
            };
            context.RouteData.Values.Add("controller", "foo");
           
            handler.PublicProcessRequest(context.HttpContext);            
        }

        [Fact]
        public void ProcessRequestWhenNoFlowFound_Throws()
        {
            var flowServiceMock = new Mock<FlowService>();
            var context = new RequestContext(new Mock<HttpContextBase>().Object, new RouteData());
            var handler = new PublicAppHandler(context)
            {
                FlowService = flowServiceMock.Object
            };
            context.RouteData.Values.Add("controller", "foo");

            Assert.Throws<FlowException>(() => handler.PublicProcessRequest(context.HttpContext));
        }      

        private sealed class PublicAppHandler : AppHandler
        {
            public PublicAppHandler(RequestContext requestContext)
                : base(requestContext)
            {
            }

            public void PublicProcessRequest(HttpContextBase httpContext)
            {
                ProcessRequest(httpContext);
            }
        }
    }

    
}